// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Repository/HDF5/Input/Dynamic/EIGCRepository.h"

#include "DBManager/Repository/HDF5/Base/HDF5RepositoryMacro.h"

HDF5_REG_REPOSITORY (EIGCRepository)

using namespace SG::DBManager::HDF5;
using namespace SG::DataStructure;

EIGCRepository::EIGCRepository (HDF5Database& database)
    : SG::DBManager::HDF5::SetRepositoryBase<SG::DataStructure::FEM::EIGCData> (database)
{}

void EIGCRepository::InitialDatasetInfo ()
{
    RegisterTableInfo<NasMainStruct> ("/SG/INPUT/DYNAMIC/EIGC/IDENTITY", MainDataset);
    RegisterIndex ("/OWN/INDEX/INPUT/DYNAMIC/EIGC", IndexDataset, GetType ());
    RegisterTableInfo<SubStruct> ("/SG/INPUT/DYNAMIC/EIGC/REGION", SubDataset);

    // 连接信号槽 当调用汇总的时候，将已有的缓存信息全部都持久化到HDF5文件中。
    GetDatabase ().GetHDF5Hub ()->m_dynamicSummarySignal.connect ([this] { Sort (); });
}

void EIGCRepository::DumpWriteCahce ()
{
    auto& writeStorage = this->GetMainCache ().m_writeStorage;

    // 设置为无顺序
    GetMainDatasetInfo ().SetIsSequential (false);

    // 主表数据
    std::vector<NasMainStruct> IDENTITYData{};
    // 附表数据
    std::vector<SubStruct> subData;

    // 转换为nastran格式数据
    OwnToNastran (writeStorage, IDENTITYData, subData);

    WriteData (MainDataset, IDENTITYData);
    WriteData (SubDataset, subData);

    // 更新Index表
    WriteIndexData (this->GetIndexDatasetInfo (), writeStorage);

    // 清空缓存
    writeStorage.clear ();
}

std::vector<EIGCRepository::DataType>*  EIGCRepository::LoadReadCache (std::size_t loadIndex)
{
    std::vector<NasMainStruct> IDENTITYData;
    LoadMainMetadata (loadIndex, IDENTITYData);

    if (IDENTITYData.empty ())
        return nullptr;

    std::vector<SubStruct> subData;
    LoadSecondaryMetadata (IDENTITYData, POS, LEN, SubDataset, subData);

    auto* cacheVector = m_cacheHelper.LookupOrCreateVector<DataType> (GetMainCache ().m_readCacheKey, IDENTITYData.size ());
    NastranToOwn (IDENTITYData, subData, *cacheVector);
    return cacheVector;
}

void EIGCRepository::SortData ()
{
    std::vector<NasMainStruct> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        GetMainDatasetInfo ().SetIsSequential (true);
        return;
    }

    std::vector<SubStruct> subData;
    GetDataset (SubDataset).read (subData);

    // 将所有数据转换
    std::vector<MainStruct> AllData{};
    NastranToOwn (IDENTITYData, subData, AllData);

    // 排序
    std::sort (AllData.begin (), AllData.end ());

    OwnToNastran (AllData, IDENTITYData, subData, true);

    // 写出数据至文件
    GetDataset (MainDataset).write (IDENTITYData);
    GetDataset (SubDataset).write (subData);

    // 重写索引
    RewriteIndexData (AllData);

    // 设置为已顺序
    GetMainDatasetInfo ().SetIsSequential (true);
}

SG::DataStructure::Common::Status EIGCRepository::FindBySId (SG::DataStructure::Common::Id sId, std::vector<MainStruct>& _OUT arrs)
{
    // 1. 确定数据是排序过的
    this->Sort ();

    // 2. 读取主表数据
    std::vector<NasMainStruct> IDENTITYData;
    if (FindMainRangeBySId (sId, IDENTITYData) == SG::DataStructure::Common::Status::STATUS_Success)
    {
        // 3. 查询副表数据
        std::vector<SubStruct> subData;
        LoadSecondaryMetadata (IDENTITYData, POS, LEN, SubDataset, subData);

        // 4. 转换数据
        NastranToOwn (IDENTITYData, subData, arrs);

        return SG::DataStructure::Common::Status::STATUS_Success;
    }
    return SG::DataStructure::Common::Status::STATUS_Failure;
}

void EIGCRepository::OwnToNastran (std::vector<MainStruct>&         own,
                                   std::vector<NasMainStruct>& _OUT IDENTITYData,
                                   std::vector<SubStruct>& _OUT     subData,
                                   bool                             isSort)
{
    subData.clear ();
    IDENTITYData.clear ();
    IDENTITYData.resize (own.size ());

    // 获取已有数据条数，主要是放在主表的POS字段
    // 如果是重新排序的时候，Pos都是从0 开始的
    size_t count = isSort ? 0 : this->GetDatasetInfo (SubDataset).GetRowCount ();

    size_t SubDatasize = 0;  // SubData需要开辟空间大小

    for (size_t i = 0; i < own.size (); ++i)
    {
        IDENTITYData[i].POS = count;
        IDENTITYData[i].LEN = own[i].m_REGIONList.size ();

        SubDatasize += IDENTITYData[i].LEN;  // 更新SubData
        // 相同变量赋值
        {
            IDENTITYData[i].SID = own[i].m_sId;
            memcpy (IDENTITYData[i].METHOD, own[i].m_METHOD, 8);
            memcpy (IDENTITYData[i].NORM, own[i].m_NORM, 8);
            IDENTITYData[i].G         = own[i].m_G;
            IDENTITYData[i].C         = own[i].m_C;
            IDENTITYData[i].E         = own[i].m_E;
            IDENTITYData[i].ND1       = own[i].m_ND1;
            IDENTITYData[i].DOMAIN_ID = own[i].m_domainId;
        }
        count += IDENTITYData[i].LEN;
    }

    subData.reserve (SubDatasize);
    for (size_t i = 0; i < own.size (); ++i)
    {
        subData.insert (subData.end (), own[i].m_REGIONList.begin (), own[i].m_REGIONList.end ());
    }
}

void EIGCRepository::NastranToOwn (std::vector<NasMainStruct>&   IDENTITYData,
                                   std::vector<SubStruct>&       subData,
                                   std::vector<MainStruct>& _OUT own)
{
    own.clear ();
    own.resize (IDENTITYData.size ());

    // 代表初始的Index 位置, 因为数据有可能是截取了附表的一部分，所有主表中根据POS找的时候需要对应一下，
    // 比如第一个主表数据中POS字段为10000， 附表的vector的数据 就是从附表中的第10000个开始对应的 也就是Index==0的
    const SG::DataStructure::Common::I64 index = IDENTITYData[0].POS;

    MainStruct const tempown;
    own.resize (IDENTITYData.size (), tempown);

    for (size_t i = 0; i < IDENTITYData.size (); i++)
    {
        auto& OwnIdent = own[i];
        auto& NasIdent = IDENTITYData[i];

        OwnIdent.m_sId = NasIdent.SID;
        memcpy (OwnIdent.m_METHOD, NasIdent.METHOD, 8);
        memcpy (OwnIdent.m_NORM, NasIdent.NORM, 8);
        OwnIdent.m_G   = NasIdent.G;
        OwnIdent.m_C   = NasIdent.C;
        OwnIdent.m_E   = NasIdent.E;
        OwnIdent.m_ND1 = NasIdent.ND1;

        OwnIdent.m_domainId = NasIdent.DOMAIN_ID;

        if (NasIdent.LEN != 0)
        {
            OwnIdent.m_REGIONList.assign (subData.begin () + NasIdent.POS - index, subData.begin () + NasIdent.POS + NasIdent.LEN - index);
        }
    }
}
